﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace XSerialization2
{
    public static class Alg
    {
        class DfsImpl
        {
            static ReferenceCollection processed = new ReferenceCollection();
            public void Run(object item, IProcessor p)
            {
                processed.Add(item);
                p.ProcessBefore(item);

                foreach (var i in p.GetChildren(item))
                {
                    if (!processed.Contains(i))
                    {
                        this.Run(i, p.GetProcessor(i));
                    }
                    else
                    {
                        p.BackReference(item, i);
                    }
                }
                p.ProcessAfter(item);
                processed.Remove(item);
            }
        }
        
        public static void Dfs(object item, IProcessor p)
        {
            new DfsImpl().Run(item, p);
        }
    }

    public class ReferenceCollection
    {
        Dictionary<int, List<object>> data = new Dictionary<int, List<object>>();
        public void Add(object o)
        {
            if (data.ContainsKey(o.GetHashCode()))
            {
                data[o.GetHashCode()].Add(o);
            }
            else
            {
                data[o.GetHashCode()] = new List<object>() { o };
            }
        }

        public void Remove(object o)
        {
            if (!Contains(o))
            {
                throw new ApplicationException();
            }
            else
            {
                data[o.GetHashCode()].Remove(o);
            }
        }

        public bool Contains(object o)
        {
            return data.ContainsKey(o.GetHashCode()) && data[o.GetHashCode()].Any(v => Object.ReferenceEquals(v, o));
        }
    }
}
